/*
 * TacticaDemo01.java
 *
 * Created on 16 de julio de 2006, 13:20
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package futbol.tacticas.concursantes2007.DaniCampeon;

import futbol.tacticas.concursantes.Tactica;

import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Collections;
import java.util.Vector;

import futbol.General;
import futbol.Partido;
import futbol.tacticas.Comando;
import futbol.tacticas.ComandoGolpearBola;
import futbol.tacticas.ComandoIrA;
import futbol.tacticas.ComandoPase;
import futbol.tacticas.ComandoTiroAPuerta;
import futbol.tacticas.SituacionJugadores;

/**
 * Esta clase implementa la "TacticaDaniInfo", as como las funciones 
 * necesarias para su ejecucin.
 * 
 * @author Daniel Peired
 */
public abstract class TacticaDaniI implements Tactica
{
  //---------------------------------------------//
  // CONSTANTES
  //---------------------------------------------//
  
  // Fuerzas
  protected static final int FUERZA_MINIMA = 4;
  protected static final int FUERZA_POCA = 5;
  protected static final int FUERZA_MUCHA = 6;
  protected static final int FUERZA_MAXIMA = 7;
  
  // Debug
  protected static boolean SHOW_TURN_TIME = false;
  protected static boolean SHOW_GOL_INFO = false;
  protected static boolean SHOW_CHUTE_INFO = false;
  protected static boolean SHOW_COMANDOS_INFO = false;
  // Debug
  protected static boolean DEBUG_MOVE_POR = false;  
  protected static boolean DEBUG_MOVE_DEF = false;
  protected static boolean DEBUG_MOVE_MED = false;
  protected static boolean DEBUG_MOVE_DEL = false;
  protected static boolean DEBUG_MOVE_ACHIQUE = false;
  protected static boolean DEBUG_BOLA_PASE = false;
  protected static boolean DEBUG_BOLA_TIRO = false;
  protected static boolean DEBUG = false;

  
  //---------------------------------------------//
  // VALORES INICIALES
  //---------------------------------------------//
  // Tiempo de chequeo de Tactica
// BORRAR !!!  
//protected static final int 600 = 1*20*10; // 600 : 1 minuto
  protected static final int CHECK_TACTICA_NORMAL = 0;
  protected static final int CHECK_TACTICA_ATAQUE = -1;
  protected static final int CHECK_TACTICA_DEFENSA = 1;
  protected static final int CHECK_TACTICA_GOLES_ATAQUE = -3; // Atacar si se pierde por 3
  protected static final int CHECK_TACTICA_GOLES_DEFENSA = 3; // Atacar si se gana de 3
//protected static final int CHECK_TACTICA_GOLES_ATAQUE = -1; // Atacar si se pierde por 3
//protected static final int CHECK_TACTICA_GOLES_DEFENSA = 1; // Atacar si se gana de 3
    
	
  //---------------------------------------------//
  // ATRIBUTOS
  //---------------------------------------------//
    
  /**
   * Estado de la partida
   */
	protected int golesFavor = 0;
	protected int golesContra = 0;
	protected long startTime = -1;
  protected long numJugada = 0;
	protected int[] goleadoresFavor;
	protected int[] goleadoresContra;
  protected int ultimoBolaFavor = -1;
  protected int ultimoBolaContra = -1;
  protected Point lastBola;
  protected double lastAngulo;
  protected double lastVelocidad;
  protected long cambioTacticaNextCheckJugada = 600;
  protected long cambioTacticaLastJugada = 0;
  protected int cambioTacticaLastTactica = 0;
  protected int cambioTacticaLastTanteoGanando = 0;
  

	
  //---------------------------------------------//
	// CONSTRUCTOR
  //---------------------------------------------//
	
  //---------------------------------------------//
	/*
	 * CONSTRUCTOR
	 */
  public TacticaDaniI()
  {
    this.goleadoresFavor = new int[11];
    this.goleadoresContra = new int[11];
    for (int i = 0; i < 11; i++) 
    {
      this.goleadoresFavor[i] = 0;
      this.goleadoresContra[i] = 0;
    }
//    this.lastDefault10 = true;
    this.golesFavor = 0;
    this.golesContra = 0;
	  this.startTime = -1;
    this.numJugada = 0;
    this.lastBola = null;
    this.lastAngulo = -1;
    this.lastVelocidad = 0;
  }
    
  //---------------------------------------------//
  // Definician de los Jugadores
  //---------------------------------------------//

  public int getFuerzaJugadores(int n)
  {
    int fuerza = 0;
    if ( 
//        (n == 0)    // 1: portero 
//        || 
        (n == 3)    // 4: libero
        ||
        (n == 6)    // 7: mediocentro
       )
    {
      fuerza = FUERZA_MINIMA;   // Maxima velocidad
    }
    else if ( 
        (n == 0)    // 1: portero   // (Forzar a que no le puedan blocar los despejes)
        || 
        (n == 1)    // 2: lateral (derecho) 
        || 
        (n == 2)    // 3: lateral (izquierdo)
        || 
        (n == 7)    // 8: interior (derecho)
        ||
        (n == 10)   //11: delantero centro
       )
    {
      fuerza = FUERZA_POCA;
    }
    else if ( 
        (n == 4)    // 5: defensa 
        || 
        (n == 5)    // 6: defensa
        ||
        (n == 8)    // 9: interior (izquierdo)
       )
    {
      fuerza = FUERZA_MUCHA;
    }
    else if ( 
        (n == 9)    //10: delantero (mediapunta) 
       )
    {
      fuerza = FUERZA_MAXIMA;
    }
      
    return fuerza;
  }
  
  //---------------------------------------------//
  // MTODOS DE LA INTERFAZ
  //---------------------------------------------//
  
  public Color getColor1()
  {
    return new Color(155, 0, 155);
//        return Color.WHITE;
  }
  
  public Color getColor2()
  {
    return new Color(125, 0, 125);
//        return Color.WHITE;
  }
  
  public Color getColorNumero()
  {
    return Color.yellow;
//        return new Color(155, 0, 155);
  }
  
  public int getFuerza(int n)
  {
    return this.getFuerzaJugadores(n);
  }
  
  //------------------------------------------------------//
  /**
   * Mtodo Principal de la Tctica
   */
  public Vector<Comando> getComandos(SituacionJugadores sj)
  {
    return this.gCs(-1, sj);
  }
  
  //------------------------------------------------------//
  /**
   * Mtodo Principal de la Tctica
   */
  public Vector<Comando> gCs(long numJugada, SituacionJugadores sj)
  {
//long iniTime = System.currentTimeMillis();
    
    //---------------------------------------------------------//
    // Aadir Eurstica sobre el Resultado y Tiempo de partido //
    //---------------------------------------------------------//
//    checkPartido(sj);
this.numJugada = numJugada;
    
    // Se garantizar que slo exista un comando de movimiento y otro de baln
    CD[] moverJugadores = new CD[11];
    CD[] golpeoBalon = new CD[11];
    Vector<CD> cd;
    
    
    cd = movimientoInicial();
    moverJugadores = ac1( moverJugadores, cd);
    
    cd = m1( sj);
    moverJugadores = ac1( moverJugadores, cd);
   
    cd = m2( sj);
    moverJugadores = ac1( moverJugadores, cd);
    
    cd = m3( sj);
    moverJugadores = ac1( moverJugadores, cd);
    
    cd = m4( sj);
    moverJugadores = ac1( moverJugadores, cd);
    
    cd = m5( sj);
    moverJugadores = ac1( moverJugadores, cd);
    
    cd = g1( sj);
    golpeoBalon = ac1( golpeoBalon, cd);
    
    cd = g2( sj);
    golpeoBalon = ac1( golpeoBalon, cd);
    
//if (SHOW_TURN_TIME)
//  printInfoPartido("Tiempo de Turno = "+(System.currentTimeMillis()-iniTime));

    Vector<Comando> comandos = new Vector<Comando>();
if (SHOW_COMANDOS_INFO)
  System.err.println(numJugada+".- \t\t BALON: = "+sj.getBola());
    for (int i = 0; i < moverJugadores.length; i++)
    {
      if (null != moverJugadores[i])
        comandos.add(moverJugadores[i].toComando());
      if (null != golpeoBalon[i])
        comandos.add(golpeoBalon[i].toComando());
if (SHOW_COMANDOS_INFO)
{
  System.err.println("\t\t Pos: "+i+"\t= "+sj.getMisJugadores()[i]);
  System.err.println("\t\t Mov: "+i+"\t= "+moverJugadores[i]);
  System.err.println("\t\t Tir: "+i+"\t= "+golpeoBalon[i]);
}
    }
    
    return comandos;
  }
  
  //------------------------------------------------------//
  // Monitorizacin de la partida  
  //------------------------------------------------------//
  
  //------------------------------------------------------//
  /**
   * Comprueba el estado del partido y actualiza el marcador
   *
   * @return tactica a utilizar
   *   0: Normal
   *   1: Defensa (vamos ganando)
   *  -1: Ataque  (vamos perdiendo)
   */
  protected int checkPartido(SituacionJugadores sj)
  {
    if (startTime < 0)
      startTime = System.currentTimeMillis();
    
    this.numJugada++;
    
    this.checkGol(sj);

    // Monitorizar la posesin 
    this.checkPosesion(sj);
    
    int result = (golesFavor-golesContra);
//    result = this.cambioTacticaLastTactica;
    
//    boolean cambioTactica = false;
//    if (this.numJugada >= this.cambioTacticaNextCheckJugada)
//    {
//      if (this.cambioTacticaLastTanteoGanando > (golesFavor - golesContra))
//      {
//        // Peor tanteador ataque?
//        if ((golesFavor - golesContra) <= CHECK_TACTICA_GOLES_ATAQUE)
//        {
//          result = CHECK_TACTICA_ATAQUE;
////          cambioTactica = true;
//        }
//        else
//        {
//          result = CHECK_TACTICA_NORMAL;
////          cambioTactica = true;
//        }
//      }
//      else
//      {
//        // Mejor tanteador ?defensa?
//        if ((golesFavor - golesContra) >= CHECK_TACTICA_GOLES_DEFENSA)
//        {
//          result = CHECK_TACTICA_DEFENSA;
////          cambioTactica = true;
//        }
//        // Mejor dejarlo como est
////        else
////        {
////          result = CHECK_TACTICA_NORMAL;
//////          cambioTactica = true;
////        }
//      }
//        
//      this.cambioTacticaLastTanteoGanando = golesFavor - golesContra;
//      this.cambioTacticaLastJugada = this.numJugada;
//      this.cambioTacticaNextCheckJugada = this.numJugada + 600;
//      this.cambioTacticaLastTactica = result;
//    }
    
    return result;
  }
  
  //------------------------------------------------------//
  /**
   * Comprueba el estado del marcador
   *
   */
  protected void checkGol(SituacionJugadores sj)
  {
//    if (this.lastDefault10)
    if (this.lastBola == null)
      this.lastBola = sj.getBola();

    if ((sj.getBola().distance(0,0) < 5) &&
        (Math.abs(this.lastBola.x) >= 155))
    {
      // Posiblemente ha habido un tanto
//      if (sj.getMisJugadores()[10].distance(0,0) < 5)
      if (this.lastBola.x <= -155)  // Mi portera
      {
        this.golesContra++;
        if (this.ultimoBolaContra >=0 )
        {
          this.goleadoresContra[this.ultimoBolaContra]++;
if (SHOW_GOL_INFO)
  this.printInfoPartido("-- Gol del jugador - "+this.ultimoBolaContra + " = "+this.goleadoresContra[this.ultimoBolaContra]);          
        }
        else
if (SHOW_GOL_INFO)
  this.printInfoPartido("-- Gol del jugador - "+this.ultimoBolaFavor + " = EN PROPIA PUERTA (estaba cerca el ="+this.ultimoBolaContra+" ).");
      }
      else
      {
        this.golesFavor++;
        if (this.ultimoBolaFavor >=0 )
        {
          this.goleadoresFavor[this.ultimoBolaFavor]++;
if (SHOW_GOL_INFO)
  this.printInfoPartido("++ Gol del jugador + "+this.ultimoBolaFavor + " = "+this.goleadoresFavor[this.ultimoBolaFavor]);
        }
        else
if (SHOW_GOL_INFO)
  this.printInfoPartido("-- Gol del jugador - "+this.ultimoBolaContra + " = EN PROPIA PUERTA (estaba cerca el ="+this.ultimoBolaFavor+" ).");
      }
      
//      this.lastDefault10 = false;

      // Imprimir informacin de la partida
if (SHOW_GOL_INFO)
      this.printInfoPartido();
    }
  }
  
  //---------------------------------------------//
  /**
   * Monitorizar la posesin
   * Actualizacin de los valores:
   * - 
   * - ultimoBolaFavor
   * - ultimoBolaContra 
   * - lastBola
   * - lastAngulo
   * - lastVelocidad
   * 
   * @param sj
   */
  protected void checkPosesion(SituacionJugadores sj)
  {
    boolean chute = true;
    int GRADOS_CHUTE = 4;
    double angle = 0;
    chute = false;
    double diffAngle = 0;
    double nuevaVelocidad = 0;
    if (this.lastBola != null)
    {
      angle = General.getAngulo(this.lastBola.getX(),this.lastBola.getY(),sj.getBola().getX(),sj.getBola().getY());
      angle = angle * 180 / Math.PI;
      diffAngle = Math.abs(this.lastAngulo - angle);
      nuevaVelocidad = General.getDistancia(this.lastBola.getX(),this.lastBola.getY(),sj.getBola().getX(),sj.getBola().getY());
//this.printInfoPartido("Angulo = "+angle + " \t pos ="+sj.getBola());
      if (diffAngle > GRADOS_CHUTE)
      {
        chute = true;
//this.printInfoPartido("** Chute : "+diffAngle);
      }
      if (nuevaVelocidad > this.lastVelocidad)
      {
//this.printInfoPartido("** Chute VELOCIDAD : "+nuevaVelocidad +" old ="+ this.lastVelocidad);
        chute = true;
      }
    }
    this.lastBola = sj.getBola();
    this.lastAngulo = angle;
    this.lastVelocidad = nuevaVelocidad;
    
    if (chute)
    {
      double bolaX = sj.getBola().x;
      double bolaY = sj.getBola().y;
      int nJug = sj.getMasCercanoDeBola();
      Point nJugPoint = sj.getMisJugadores()[nJug];
      int nContrario = sj.getContrarioMasCerca(bolaX, bolaY);
      Point nContrarioPoint = sj.getContrario()[nContrario];
      if (((nJug > 0) && (nContrario > 0)) || 
          (diffAngle > 45))
      {
        double distJugBola = nJugPoint.distance(bolaX, bolaY);
        double distContrarioBola = nContrarioPoint.distance(bolaX, bolaY);
        if (distJugBola <= distContrarioBola)
        {
          if (distJugBola <= 5)
          {
            this.ultimoBolaFavor = nJug; 
            this.ultimoBolaContra = -1 * nContrario; 
          }
        } 
        else
        {
          if (distContrarioBola <= 5)
          {
            this.ultimoBolaFavor = -1 * nJug; 
            this.ultimoBolaContra = nContrario; 
          }
        }
if (SHOW_CHUTE_INFO)
  this.printInfoPartido("Chute Favor= "+ultimoBolaFavor + " \t ultimoBolaContra = "+ultimoBolaContra);
      }
    }
  }
  
  //---------------------------------------------//
  /**
   *
   */
  protected void printInfoPartido()
  {
    this.printInfoPartido("");
  }
  
  //---------------------------------------------//
  /**
   *
   */
  protected void printInfoPartido(String mensaje)
  {
    long tiempo = (((System.currentTimeMillis()-startTime- (golesContra+golesFavor)*1500-2*1000)/1000) );
//    System.err.println("tiempo="+tiempo+" sg. \t resultado = "+golesFavor+" - "+golesContra + "\t : "+mensaje);
    System.err.println(numJugada+"-  T="+tiempo+" sg. \t R= "+golesFavor+" - "+golesContra + "\t Turno="+this.getNombre()+ "\t : "+mensaje);
  }

  //---------------------------------------------//
  /**
   *
   */
  protected static String toString(Point punto)
  {
    return (new String("x="+punto.x+" , y="+punto.y));  
  }
    
  //---------------------------------------------//
  /**
   *
   */
  protected static CD[] ac1(CD[] comandosActuales, 
                                                  Vector<CD> comandosNuevos)
  {
    CD[] comandosActualizados = new CD[comandosActuales.length];
    CD comando;
    for (int i = 0; i < comandosActuales.length; i++)
      comandosActualizados[i] = comandosActuales[i];
    for (int i = 0; i < comandosNuevos.size(); i++)
    {
      comando = (CD) comandosNuevos.elementAt(i);
//      if (comandosActuales[comando.getJugador()] == null)
      comandosActualizados[comando.getJugador()] = comando;
//if (DEBUG)
    }
    return comandosActualizados;
  }
  
  //---------------------------------------------//
  // MTODOS AUXILIARES
  //---------------------------------------------//
  
  //---------------------------------------------//
  /**
   * Calcula las coordenadas desde la situacin del contrario indicado,
   * con el radio de marcaje, si el baln se dirige hacia dicho contrario.
   * Si no se trata de un pase, se intenta colocar en posicin de rechace con
   * el mismo radio, pero hacia el centro de su propia portera.
   */
  protected static Point cortarPaseDireccionDelantero(int nContrario, int radio, SituacionJugadores sj)
  {
    Point marcaje = sj.getContrario()[nContrario];
    int newX, newY;
    Point bola = sj.getBola();
//    double angulo = General.getAngulo(marcaje.getX(), marcaje.getY(), bola.getX(), bola.getY()) * 180 / Math.PI;
    if (( marcaje.x < bola.x) 
//        && 
//      ((angulo > (Math.PI/2)) && (angulo < ((Math.PI*3)/2)))
      )
    {
      newX = marcaje.x + radio;// * Math.sin(angulo) ;
      if (marcaje.y > bola.y)
        newY = marcaje.y - radio;
      else
        newY = marcaje.y + radio;;
    }
    else
    {
      // Posicin para el rechace
      newX = marcaje.x - radio;  // marcaje.x - (160 * (-1))
      if (newX < (0 - 160))
        newX = radio - 160;
//      if (marcaje.y < 0)
      if (marcaje.y > bola.y)
        newY = marcaje.y - radio;
      else
        newY = marcaje.y + radio;;
    }
    marcaje = new Point( newX, newY );
    return marcaje;
  }
  
  //---------------------------------------------//
  /**
   * Calcula las desviacin adecuada para el tiro.
   */
  protected static int calcularDesviacionTiro(Point delantero, Point portero)
  {
    int desviacion = 0;
    
//    if (delantero.y > 30)
    if (delantero.y > 70)
    {
      // Disparo escorado
      if (portero.y < (30/2))
        // Disparar al primer palo
//        desviacion = 1;
        desviacion = 10;
else      
  // Disparo cruzado
  desviacion = -10;
    }
    else if (delantero.y > 0)
    {
      
      if (portero.y > 0)
        // Disparo cruzado
        desviacion = -10;
else      
  // Disparo casi al primer palo
  desviacion = 1;
    }
//    else if (delantero.y < (0 - 30))
    else if (delantero.y < (0 - 70))
    {
      // Disparo escorado
      if (portero.y < ((0-30)/2))
        // Disparar al primer palo
//        desviacion = -1;
desviacion = -10;
else      
  // Disparo cruzado
  desviacion = 10;
    }
    else
    {
      if (portero.y < 0)
        // Disparo cruzado
        desviacion = 10;
else      
  // Disparo casi al primer palo
  desviacion = -1;
    }
if (DEBUG_BOLA_TIRO)    
System.err.println(" --------calcularDesviacionTiro ---  "+desviacion+"\t delantero="+delantero+"\t portero="+portero); 

// BORRAR
//desviacion = -20;

    return desviacion;
  }

  //---------------------------------------------//
  /**
   * Indica si la pelota se encuentra dentro del propio rea.
   */
  protected static boolean isArea(Point pelota)
  {
    boolean result = false;
    if ((pelota.getX() < -110) && ( Math.abs(pelota.getY()) < 70))
      result = true;
    
    return result;
  }
  
  //---------------------------------------------//
  /**
   * Devuelve la distancia a la pelota del contrario ms cercano a ella.
   */
  protected static double distContrarioCercaPelota(SituacionJugadores sj)
  {
    double distancia;
    Point pelota = sj.getBola();
    int nRivalCercaPelota = sj.getContrarioMasCerca(pelota.x, pelota.y);
    Point posRival = sj.getContrario()[nRivalCercaPelota];
    // distancia = General.getDistancia(x1, y1, x2, y2);
    distancia = posRival.distance(pelota);

    return distancia;
  }
  
  //---------------------------------------------//
  /**
   * Calcula el mejor pase a jugadores cercanos (limitado por limitePase).
   * Si el pase no fuera posible (limiteRiesgo), calculara unas coordenadas
   * libre de contrarios para un despeje.
   */
  protected static Point calculaMejorPase(SituacionJugadores sj,
                                          int jugador, boolean soloAdelante,
                                          int limitePaseMin,int limitePaseMax, 
                                          int limiteRiesgo)
  {
    Point mejorJugada = null;
    int limiteRiesgoAngulo = limiteRiesgo / 2;
    
    Point jugadorPunto = sj.getMisJugadores()[jugador];
    Point punto;
    Vector situacionesPase = new Vector();
    double distancia;
if (DEBUG_BOLA_PASE)    
System.err.println(" --------calculaMejorPase ---  "+jugador+"\t  :"+toString(jugadorPunto)+"\t - slmites : min="+limitePaseMin+"\t max="+limitePaseMax+"\t riesgo="+limiteRiesgo); 
    for (int i = 0; i < sj.getMisJugadores().length; i++) 
    {
      if (i != jugador)
      {
        punto = sj.getMisJugadores()[i];
        if ((punto.x < jugadorPunto.x) && soloAdelante)
        {
          // descartado el pase atrs
        }
        else
        {
          distancia = jugadorPunto.distance(punto);
          // Descartar distancias
          if ((distancia >= limitePaseMin) &&
              (distancia <= limitePaseMax))
          {
            situacionesPase.add(new SP(i, distancia));
          }
        }
      }
    }
    // Primero , ordenamos el vector por distancia de pase (no hay rivales detectados por el momento)
    Collections.sort(situacionesPase);
    double angulo, anguloRival;
    SP situacionPase;
    for (int i = 0; i < situacionesPase.size(); i++) 
    {
      situacionPase = (SP) situacionesPase.elementAt(i);
      
if (DEBUG_BOLA_PASE)    
System.err.println(" +++ "+i+".- n="+situacionPase.nJugador+"\t dist="+situacionPase.distancia);
//      // Descartar distancias
//      if ((situacionPase.distancia >= limitePaseMin) &&
//          (situacionPase.distancia <= limitePaseMax))
//      {
        punto = sj.getMisJugadores()[situacionPase.nJugador];
        // Calcular angulo de pase
        angulo = General.getAngulo(jugadorPunto.x, jugadorPunto.y,
                                    punto.x, punto.y);
        angulo = angulo * 180 / Math.PI;
        // Calcular posibles rivales cercanos
        Rectangle areaPase = new Rectangle( jugadorPunto.x, 
                                            jugadorPunto.y,
                                            punto.x - jugadorPunto.x,
                                            punto.y - jugadorPunto.y
                                            );
        if (jugadorPunto.x > punto.x)
        {
          areaPase.x = punto.x;
          areaPase.width = jugadorPunto.x - punto.x;
        }
        if (jugadorPunto.y > punto.y)
        {
          areaPase.y = punto.x;
          areaPase.height = jugadorPunto.y - punto.y;
        }
        // Ajuste de margenes por proximidad de rivales
        areaPase.x = areaPase.x - limiteRiesgo;
        areaPase.width = areaPase.width + limiteRiesgo*2;
        areaPase.y = areaPase.y - limiteRiesgo;
        areaPase.height = areaPase.height + limiteRiesgo*2;
        for (int j = 0; j < sj.getContrario().length; j++) 
        {
          if (areaPase.contains(sj.getContrario()[j]))
          {
            // Rival en rea de pase
            anguloRival = General.getAngulo(jugadorPunto.x, jugadorPunto.y,
                                    sj.getContrario()[j].x, sj.getContrario()[j].y);
            anguloRival = anguloRival * 180 / Math.PI;
            
            if (Math.abs(angulo - anguloRival) < limiteRiesgoAngulo)
            {
              // Contrario Cerca
              situacionPase.addRivalCerca(j, jugadorPunto.distance(sj.getContrario()[j]));
if (DEBUG_BOLA_PASE)    
System.err.println(" --- "+j+".- "+toString(sj.getContrario()[j])+"\t anguloRival="+anguloRival + " / "+angulo + "  < lim="+limiteRiesgoAngulo);
            }
            else
if (DEBUG_BOLA_PASE)    
System.err.println("\t  --- "+j+".- "+toString(sj.getContrario()[j])+"\t anguloRival="+anguloRival + " / "+angulo + "  > lim="+limiteRiesgoAngulo);
          }
        }
//      }
//      else
//System.err.println(" --- Fuera de los lmites : min="+limitePaseMin+"\t max="+limitePaseMax);        
    }
    
// Ahora , ordenamos el vector por distancia y rivales detectados (1 si no hay rivales cerca)
Collections.sort(situacionesPase);
if (DEBUG_BOLA_PASE)    
System.err.println(" --------calculaMejorPase CON CONTRARIOS ---  "+jugador+"\t  :"+toString(jugadorPunto));
int mejorPase = -1;
int limiteRivales = 0;
for (int i = 0; i < situacionesPase.size(); i++) 
{
  situacionPase = (SP) situacionesPase.elementAt(i);
  if (mejorPase == -1)
  {
    if (situacionPase.rivalesCerca.size() <= limiteRivales)
      mejorPase = situacionPase.nJugador;
  }
if (DEBUG_BOLA_PASE)    
System.err.println(" *** "+i+".- n="+situacionPase.nJugador+"\t dist="+((int)situacionPase.distancia)+"\t numRivales="+situacionPase.rivalesCerca.size());
}
if (mejorPase != -1)
  mejorJugada = sj.getMisJugadores()[mejorPase];
else
{
  // Si no hay ningn pase posible, despejar adelante junto a la banda.
  if (jugadorPunto.y > 0)
  {
    mejorJugada = new Point(jugadorPunto.x+100, jugadorPunto.y+100);
  }
  else
  {
    mejorJugada = new Point(jugadorPunto.x+100, jugadorPunto.y-100);
  }
}
if (DEBUG_BOLA_PASE)    
System.err.println(" Mejor jugada = "+mejorPase+"\t => "+mejorJugada);
if (DEBUG_BOLA_PASE)    
System.err.println(" ------------------------------------ ");

    return mejorJugada;
  }
  
  //---------------------------------------------//
  /**
   * Retorna los identificadores de los delanteros rivales. 
   * stos sern aquello que estn a distancia de tiro.
   * @see #65
   */
  protected static int[] getDelanterosRivales(SituacionJugadores sj)
  {
    Vector delanteros = new Vector();
    for (int i = 0; i < 11; i++)
    {
      if (sj.getContrario()[i].x <= 65)
        delanteros.add(new Integer(i));
    }
    int[] result = new int[delanteros.size()];
    for (int i = 0; i < result.length; i++)
    {
      result[i] = ((Integer) delanteros.elementAt(i)).intValue();
    }

    return result;
  }
  
//    protected static boolean delanteroMarcado(SituacionJugadores sj, int nContrario, int[] excluir)
//    {
//      boolean result = false;
//      int[] info = sj.getInfoMasCercano(sj.getMisJugadores(), sj.getContrario()[nContrario], excluir, false);
//      if (info[0] > 0)
//      {
//        int dist =  (int)General.getDistancia(sj.getContrario()[nContrario].getX(), sj.getContrario()[nContrario].getY(), punto.getX(), punto.getY());
//        if (info[1] < dist)
//          result = true;
//      }
//      return result; 
//    }
  
  //---------------------------------------------//
  // MTODOS AUXILIARES (vacos)
  //---------------------------------------------//

  //---------------------------------------------//
  /**
   * Retorna los identificadores de los porteros. 
   */
  protected int[] getPortero()
  {
    return new int[0];
  }
  //---------------------------------------------//
  /**
   * Retorna los identificadores de los defensas. 
   */
  protected int[] getDefensas()
  {
    return new int[0];
  }
  //---------------------------------------------//
  /**
   * Retorna el identificador del defensa libre. 
   */
  protected int getLibero()
  {
    return 0;
  }
  //---------------------------------------------//
  
  /**
   * Retorna los identificadores de los medios. 
   */
  protected int[] getMedios()
  {
    return new int[0];
  }
  //---------------------------------------------//
  /**
   * Retorna el identificador del medio organizador. 
   */
  protected int getMedioCentro()
  {
    return 0;
  }
  
  //---------------------------------------------//
  /**
   * Retorna los identificadores de los delanteros. 
   */
  protected int[] getDelanteros()
  {
    return new int[0];
  }
  //---------------------------------------------//
  /**
   * Retorna el identificador del delantero mas adelantado. 
   */
  protected int getDelanteroCentro()
  {
    return 0;
  }
  
  //---------------------------------------------//
  /**
   * Retorna los movimientos iniciales.
   */
  protected Vector<CD> movimientoInicial()
  {
    Vector<CD> comandos = new Vector<CD>();
    for (int n = 0; n < 11; n++)
    {
      comandos.add(CD.newComandoIrA(n, this.getXInicial(n), this.getYInicial(n)));
    }
    return comandos;
  }

  //---------------------------------------------//
  /**
   * Retorna los movimientos del portero.
   */
  protected Vector<CD> m1( SituacionJugadores sj)
  {
    Vector<CD> comandos = new Vector<CD>();
    return comandos;
 }

  //---------------------------------------------//
  /**
   * Retorna los movimientos de la defensa.
   */
  protected Vector<CD> m2( SituacionJugadores sj)
  {
    Vector<CD> comandos = new Vector<CD>();
    return comandos;
  }

  //---------------------------------------------//
  /**
   * Retorna los movimientos del mediocampo.
   */
  protected Vector<CD> m3( SituacionJugadores sj)
  {
    Vector<CD> comandos = new Vector<CD>();
    return comandos;
  }
  
  //---------------------------------------------//
  /**
   * Retorna los movimientos de la delantera.
   */
  protected Vector<CD> m4( SituacionJugadores sj)
  {
    Vector<CD> comandos = new Vector<CD>();
    return comandos;
  }
  
  //---------------------------------------------//
  /**
   * Retorna los movimientos relativos al achique del baln.
   */
  protected Vector<CD> m5( SituacionJugadores sj)
  {
    Vector<CD> comandos = new Vector<CD>();
    return comandos;
  }
  
  //---------------------------------------------//
  /**
   * Retorna los pases
   */
  protected Vector<CD> g1( SituacionJugadores sj)
  {
    Vector<CD> comandos = new Vector<CD>();
    return comandos;
  }

  //---------------------------------------------//
  /**
   * Retorna los disparos a puerta
   */
  protected Vector<CD> g2( SituacionJugadores sj)
  {
    Vector<CD> comandos = new Vector<CD>();
    return comandos;
  }

  
}  
  //---------------------------------------------//
  //---------------------------------------------//
  // CLASES AUXILIARES
  //---------------------------------------------//
  
  //---------------------------------------------//
  //---------------------------------------------//
 /**
   * Esta clase almacena la situcin de un jugador con respecto a otro.
   */
  class SP implements Comparable
  {
    /**
     * Nmero del Jugador.
     */
    protected int nJugador;
    
    /**
     * Distancia
     */
    protected double distancia;
    
    /**
     * Vector de rivales cercanos al pase
     */
    protected Vector rivalesCerca;
    
    //---------------------------------------------//
    /**
     * Constructor.
     * 
     * @param nJugador
     * @param distancia
     */
    protected SP(int nJugador, double distancia)
    {
      this.nJugador = nJugador;
      this.distancia = distancia;
      this.rivalesCerca = new Vector();
    }
    
    //---------------------------------------------//
    /**
     * Aade la situacin de un nuevo rival, y retorna
     * el nmero de rivales cercanos.
     */
    public int addRivalCerca(int nJugadorRival, double distanciaRival)
    {
      SP rival = new SP(nJugadorRival, distanciaRival);
      this.rivalesCerca.add(rival);
      return this.rivalesCerca.size();
    }
    
    //---------------------------------------------//
    /**
     * Comparador
     */
    public int compareTo(Object o)
    {
      int result = -1;
      if (o instanceof SP)
      {
        result = this.rivalesCerca.size() - ((SP) o).rivalesCerca.size();
        if (result == 0)
          result = (int) Math.round(this.distancia - ((SP) o).distancia); 
      }
      return result;
    }
    
  }

  //---------------------------------------------//
  //---------------------------------------------//
  /**
   * Esta clase facilita el acceso a los comandos
   */
  class CD //extends Comando
  {
    //---------------------------------------------//
    // CONSTANTES
    //---------------------------------------------//
    
    // Identificador del comando
    protected static final int IR_A = 1;
    protected static final int GOLPEAR_BOLA = 2;
    protected static final int PASE = 3;
    protected static final int TIRO_PUERTA = 4;

    /**
     * Identificador del comando
     */
    protected int idComando;
    
    /**
     * Nmero del Jugador.
     */
    protected int nJugador;
    
    /**
     * x
     */
    protected double x;
    
    /**
     * y
     */
    protected double y;
    
    /**
     * Desviacion
     */
    protected int desviacion;
    
    /**
     * Nmero del Jugador Destino.
     */
    protected int nJugadorDestino;
    
    //---------------------------------------------//
    /**
     * Constructor.
     * 
     * @param nJugador
     * @param distancia
     */
    private CD(int idComando, int nJugador, double x, double y, int desviacion, int nJugadorDestino)
    {
      this.idComando = idComando;
      this.nJugador = nJugador;
      this.x = x;
      this.y = y;
      this.desviacion = desviacion;
      this.nJugadorDestino = nJugadorDestino;
    }
    
    //---------------------------------------------//
    /**
     * Ejecuta el comando (ERROR: Deben de convertirse antes a un comando vlido)
     */
    public void ejecutar(Partido p)
    {
      System.err.println("\n-- ERROR DE EJECUCION. NO SE HA CONVERTIDO EL COMANDO : "+this);
    }
    
    public int getJugador()
    {
      return this.nJugador;
    }
          
    //---------------------------------------------//
    /**
     * Convierte el comando a un comando vlido
     */
    protected Comando toComando()
    {
      Comando comando = null;
      
      if (this.idComando == GOLPEAR_BOLA)
        comando = new ComandoGolpearBola(this.nJugador, this.x, this.y);
      else if (this.idComando == IR_A)
        comando = new ComandoIrA(this.nJugador, this.x, this.y);
      else if (this.idComando == PASE)
        comando = new ComandoPase(this.nJugador, this.nJugadorDestino);
      else if (this.idComando == TIRO_PUERTA)
        comando = new ComandoTiroAPuerta(this.nJugador, this.desviacion);
      
      return comando;
    }

    //---------------------------------------------//
    /**
     * Convierte el comando a una cadena de texto
     */
    public String toString()
    {
      StringBuffer str = new StringBuffer("Comando=");
      
      if (this.idComando == GOLPEAR_BOLA)
        str.append( " GOLPEAR_BOLA \t Jug="+this.nJugador+" , x="+ this.x+" , y="+ this.y);
      else if (this.idComando == IR_A)
        str.append( " IR_A \t Jug="+this.nJugador+" , x="+ this.x+" , y="+ this.y);
      else if (this.idComando == PASE)
        str.append( " PASE \t Jug="+this.nJugador+" , destino="+ this.nJugadorDestino);
      else if (this.idComando == TIRO_PUERTA)
        str.append( " TIRO_PUERTA \t Jug="+this.nJugador+" , desviacion="+ this.desviacion);
      
      return str.toString();
    }

    //---------------------------------------------//
    /**
     * Crea los comando de depuracion.
     */
    protected static CD newComandoGolpearBola(int nJugador, double x, double y)
    {
      CD comandoDani;
      comandoDani = new CD(GOLPEAR_BOLA, nJugador, x, y, 0, 0);
      return comandoDani;
    }
    protected static CD newComandoIrA(int nJugador, double x, double y)
    {
      CD comandoDani;
      comandoDani = new CD(IR_A, nJugador, x, y, 0, 0);
      return comandoDani;
    }
    protected static CD newComandoPase(int nJugador, int nJugadorDestino)
    {
      CD comandoDani;
      comandoDani = new CD(PASE, nJugador, 0, 0, 0, nJugadorDestino);
      return comandoDani;
    }
    protected static CD newComandoTiroAPuerta(int nJugador, int desviacion)
    {
      CD comandoDani;
      comandoDani = new CD(TIRO_PUERTA, nJugador, 0, 0, desviacion, 0);
      return comandoDani;
    }
    
  }
  
  
//}
